package de.tudarmstadt.fgbs.cafe.importexport;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.tudarmstadt.fgbs.cafe.exception.FlawedConfigurationException;
import de.tudarmstadt.fgbs.cafe.structure.Bahnhof;
import de.tudarmstadt.fgbs.cafe.structure.Fahrplan;
import de.tudarmstadt.fgbs.cafe.structure.Wegpunkt;
import de.tudarmstadt.fgbs.cafe.structure.Zuglauf;

public class ImportAgent implements ImportInterface {

    /**
     * The log which is used to log all behaviors of this class.
     */
    private static Log LOG = LogFactory.getLog(ImportAgent.class);

    private ImportCoreInterface core;

    public ImportAgent(ImportCoreInterface core) {
	if (LOG.isTraceEnabled())
	    LOG.trace("# a new instance of ImportAgent is created");
	this.core = core;
    }

    @Override
    public Fahrplan importFPL(String location) {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ImportAgent.importFPLHeader(" + location + ")");
	try {
	    FileReader fr = new FileReader(location);
	    BufferedReader reader = new BufferedReader(fr);
	    Fahrplan fpl = parseFPL(reader);
	    fpl.setName(extractName(location));
	    return fpl;
	} catch (FileNotFoundException e) {
	    LOG.error("# an exception occured: " + e.getMessage());
	} catch (IOException e) {
	    LOG.error("# an IO exception occured: " + e.getMessage());
	} catch (FlawedConfigurationException e) {
	    LOG.error("# an configuration exception occured: " + e.getMessage());
	}
	return null;
    }

    private String extractName(String location) {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ImportAgent.extractName(" + location + ")");
	String parts[] = location.split("\\" + File.separator);
	if (parts.length > 0)
	    return parts[parts.length - 1];
	else
	    return null;
    }

    private Fahrplan parseFPL(BufferedReader reader) throws IOException,
	    FlawedConfigurationException {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ImportAgent.parseFPL(" + reader.toString() + ")");
	reader.mark(100);
	String currentLine = reader.readLine();
	Fahrplan tempFPL = new Fahrplan();
	Map<String, Bahnhof> bahnhofMap = core.retrieveBahnhofMap();
	HashMap<String, Zuglauf> zuglaufMap = new HashMap<String, Zuglauf>();
	reader.reset();

	while (currentLine != null) {
	    Zuglauf currLauf = new Zuglauf();
	    parseLaufHeader(currLauf, reader);
	    parseLaufStations(currLauf, reader, bahnhofMap);

	    zuglaufMap.put(currLauf.getNumber(), currLauf);
	    System.out.println(currentLine);
	    reader.mark(100);
	    currentLine = reader.readLine();
	    reader.reset();
	}
	tempFPL.setZuglaeufe(linkZL(zuglaufMap));

	return tempFPL;
    }

    private List<Zuglauf> linkZL(HashMap<String, Zuglauf> zuglaufMap) {
	List<Zuglauf> zuglauefe = new ArrayList<Zuglauf>();
	zuglauefe.addAll(zuglaufMap.values());

	for (Iterator<Zuglauf> it = zuglauefe.iterator(); it.hasNext();) {
	    Zuglauf currentZL = it.next();
	    if (currentZL.getKommtAusNr() != null
		    && currentZL.getKommtAusNr().length() > 1)
		currentZL
			.setKommtAus(zuglaufMap.get(currentZL.getKommtAusNr()));
	    if (currentZL.getWirdZuNr() != null
		    && currentZL.getWirdZuNr().length() > 1)
		currentZL.setWirdZu(zuglaufMap.get(currentZL.getWirdZuNr()));
	}

	return zuglauefe;
    }

    private void parseLaufStations(Zuglauf currLauf, BufferedReader reader,
	    Map<String, Bahnhof> bahnhofMap) throws IOException {
	List<Wegpunkt> strecke = new ArrayList<Wegpunkt>();
	String currentLine = reader.readLine();
	if (currentLine != null) {
	    String[] lineElements = currentLine.split("\t");
	    while (lineElements != null && lineElements[0] != null
		    && !lineElements[0].contains(":")) {
		Wegpunkt currentPunkt = new Wegpunkt();
		System.out.println(currentLine);
		Bahnhof currentBhf = bahnhofMap.get(lineElements[0]);
		currentPunkt.setBahnhof(currentBhf);
		currentPunkt.setAnkunft(lineElements[1]);
		currentPunkt.setAbfahrt(lineElements[2]);
		if (lineElements[3].equals("W"))
		    currentPunkt.setWende(true);
		else if (lineElements[3].equals("D"))
		    currentPunkt.setDurchfahrt(true);
		if (lineElements.length > 4) {
		    currentPunkt.setRegelgleis(lineElements[4]);
		}
		if (lineElements.length > 7)
		    currentPunkt.setAufenthalt(Integer
			    .parseInt(lineElements[7]));
		else
		    currentPunkt.setAufenthalt(0);
		strecke.add(currentPunkt);
		reader.mark(100);
		currentLine = reader.readLine();
		if (currentLine != null)
		    lineElements = currentLine.split("\t");
		else
		    lineElements = null;
	    }
	    currLauf.setStationen(strecke);
	    reader.reset();
	}
    }

    private void parseLaufHeader(Zuglauf currLauf, BufferedReader reader)
	    throws IOException {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ImportAgent.parseLaufHeader(" + currLauf.toString()
		    + ", " + reader.toString() + ")");
	String currentLine = reader.readLine();
	if (currentLine != null) {
	    String[] lineElements = currentLine.split("\t");
	    while (lineElements != null && lineElements[0].contains(":")) {
		String key = lineElements[0];
		if (key.equals("Zugnummer:")) {
		    String zn = lineElements[1].replaceAll("[^\\d]", "");
		    String gattung = lineElements[1].replaceAll("[\\d]", "");
		    if (zn.equals("6050"))
			System.out.print("X");
		    currLauf.setNumber(zn);
		    currLauf.setGattung(gattung);
		} else if (key.equals("Wendezug:")) {
		    if (lineElements[1].equals("1"))
			currLauf.setWende(true);
		    else
			currLauf.setWende(false);
		} else if (key.equals("Fahrbereit:")) {
		    if (lineElements[1].equals("1"))
			currLauf.setReady(true);
		    else
			currLauf.setReady(false);
		} else if (key.equals("Personenzug:")) {
		    if (lineElements[1].equals("1"))
			currLauf.setPersonenZug(true);
		    else
			currLauf.setPersonenZug(false);
		} else if (key.equals("Umlauf:")) {
		    currLauf.setUmlauf(Integer.parseInt(lineElements[1]));
		} else if (key.equals("Baureihe:")) {
		    currLauf.setBaureihe(Integer.parseInt(lineElements[1]));
		} else if (key.equals("Plus:")) {
		    currLauf.setPlus(Short.parseShort(lineElements[1]));
		} else if (key.equals("Betriebstage:")) {

		} else if (key.equals("Vmax:")) {
		    currLauf.setVmax(Integer.parseInt(lineElements[1]));
		} else if (key.equals("Wende aus:") || key.equals("Kommt aus:")) {
		    currLauf.setKommtAusNr(lineElements[1]);
		} else if (key.equals("Wende auf:")
			|| key.equals("Weiter als:")) {
		    currLauf.setWirdZuNr(lineElements[1]);
		} else {
		    if (LOG.isWarnEnabled())
			LOG.trace("# unknown header field encountered: " + key);
		}

		reader.mark(100);
		currentLine = reader.readLine();
		if (currentLine != null)
		    lineElements = currentLine.split("\t");
		else
		    lineElements = null;
	    }
	    reader.reset();
	}
    }
}
